歡迎來到「Laravel Pest TDD 實戰:從零開始的測試驅動開發」系列!
想像一下,你是一位新手開發者,剛加入一個重視程式品質的團隊。主管交給你第一個任務:「我們要建立一個 Laravel 專案,而且要從第一天就導入測試文化。」聽起來很有挑戰性?別擔心,讓我們從最基礎的開始,一步步建立起 TDD 的基礎。
今天是我們 TDD 旅程的第一天,我們要設置 Laravel + Pest 的開發環境,並寫下第一個測試。就像學開車一樣,我們先在安全的練習場地熟悉基本操作。
今天結束後,你將學會:
第一階段:打好基礎(Day 1-10)
├── Day 01 - 環境設置與第一個測試 ★ 今天在這裡
├── ...
└── (更多精彩內容待續)
首先建立一個全新的 Laravel 專案:
composer create-project laravel/laravel laravel-tdd-demo
cd laravel-tdd-demo
Pest 是 Laravel 生態系統中現代化的測試框架,提供更簡潔的語法:
composer require pestphp/pest --dev --with-all-dependencies
初始化 Pest:
./vendor/bin/pest --init
查看 tests/Pest.php
檔案,這是 Pest 的全域設定:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(Tests\TestCase::class)->in('Feature');
uses(
Tests\TestCase::class,
RefreshDatabase::class,
)->in('Feature');
我們可以為單元測試新增設定,更新 tests/Pest.php
:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(Tests\TestCase::class)->in('Feature');
uses(
Tests\TestCase::class,
RefreshDatabase::class,
)->in('Feature');
// 單元測試設定
uses()->in('Unit');
Laravel 的測試檔案預設分為兩種:
tests/Unit/
: 單元測試,測試單一類別或函數tests/Feature/
: 功能測試,測試完整的功能流程今天我們專注於單元測試。
讓我們從最簡單的例子開始 - 一個計算機類別。
建立 tests/Unit/Day01/CalculatorTest.php
:
<?php
// 先寫測試,這時 Calculator 類別還不存在
use App\Calculator;
it('adds two numbers correctly', function () {
$calculator = new Calculator();
$result = $calculator->add(2, 3);
expect($result)->toBe(5);
});
./vendor/bin/pest
你會看到測試失敗的訊息,因為 Calculator
類別還不存在。這就是 TDD 的「紅燈」階段 - 先寫測試,看它失敗。
建立 app/Calculator.php
:
<?php
namespace App;
class Calculator
{
public function add(int $a, int $b): int
{
return $a + $b;
}
}
再次執行測試:
./vendor/bin/pest
現在測試應該通過了!這就是「綠燈」階段。
更新 tests/Unit/Day01/CalculatorTest.php
:
<?php
use App\Calculator;
describe('Calculator', function () {
beforeEach(function () {
$this->calculator = new Calculator();
});
it('adds two numbers correctly', function () {
$result = $this->calculator->add(2, 3);
expect($result)->toBe(5);
});
it('adds negative numbers correctly', function () {
$result = $this->calculator->add(-2, 3);
expect($result)->toBe(1);
});
it('subtracts two numbers correctly', function () {
$result = $this->calculator->subtract(5, 3);
expect($result)->toBe(2);
});
it('multiplies two numbers correctly', function () {
$result = $this->calculator->multiply(4, 3);
expect($result)->toBe(12);
});
it('divides two numbers correctly', function () {
$result = $this->calculator->divide(10, 2);
expect($result)->toBe(5);
});
it('handles division by zero', function () {
expect(fn() => $this->calculator->divide(10, 0))
->toThrow(DivisionByZeroError::class);
});
});
更新 app/Calculator.php
:
<?php
namespace App;
class Calculator
{
public function add(int $a, int $b): int
{
return $a + $b;
}
public function subtract(int $a, int $b): int
{
return $a - $b;
}
public function multiply(int $a, int $b): int
{
return $a * $b;
}
public function divide(int $a, int $b): int
{
if ($b === 0) {
throw new \DivisionByZeroError('Division by zero');
}
return intval($a / $b);
}
}
./vendor/bin/pest
所有測試都應該通過!
Pest 提供多種執行測試的方式:
# 監聽模式
./vendor/bin/pest --watch
# 單次執行
./vendor/bin/pest
# 使用詳細輸出
./vendor/bin/pest --verbose
# 產生覆蓋率報告(需要安裝 Xdebug)
./vendor/bin/pest --coverage
# 平行執行測試
./vendor/bin/pest --parallel
如果遇到「Class 'App\Calculator' not found」錯誤,確認:
composer dump-autoload
重新載入自動載入如果遇到 Class 'DivisionByZeroError' not found
錯誤,確保你的 PHP 版本 >= 7.0。
確保測試檔案符合以下命名規則之一:
*Test.php
tests/
目錄下每個測試都應該遵循 AAA 模式:
試著為計算機新增以下功能:
modulo($a, $b)
方法power($base, $exponent)
方法💡 提示:記得先寫測試再實作功能!
it()
: 個別測試案例,使用自然語言描述describe()
: 測試群組,組織相關測試expect()
: 斷言函數,驗證結果beforeEach()
: 在每個測試前執行tests/Unit/
目錄tests/Unit/Day01/CalculatorTest.php
)Test.php
後綴命名今天我們完成了 TDD 學習旅程的第一步!透過建立 Laravel + Pest 環境,我們學會了:
今天我們成功建立了 Laravel + Pest 的測試環境,並完成了第一個單元測試。雖然例子很簡單,但我們已經體驗了完整的 TDD 流程:
記住,TDD 不只是一種測試技術,更是一種設計思維。透過先寫測試,我們被迫思考程式的介面和行為,這能幫助我們寫出更好的程式碼。
明天我們將深入了解斷言函數的威力,學習如何寫出更有表達力的測試。準備好了嗎?繼續加油! 💪